/**
 * 断点配置接口
 */
interface Breakpoint {
    width: number;
    columns: number;
}

/**
 * 瀑布流布局选项接口
 */
interface WaterfallOptions {
    /** 容器元素 */
    container: HTMLElement;
    /** 容器宽度 */
    width?: string;
    /** 列数 */
    count?: number;
    /** 间距 */
    gap?: string;
    /** 项目类名 */
    itemClass?: string;
    /** 是否响应式 */
    responsive?: boolean;
    /** 响应式断点配置 */
    breakpoints?: Breakpoint[];
    /** 是否启用动画 */
    animation?: boolean;
    /** 动画时长(ms) */
    animationDuration?: number;
}

/**
 * 项目数据接口
 */
interface ItemData {
    /** 项目高度 */
    height: number;
    /** 所在列 */
    column: number;
    /** 项目索引 */
    index: number;
}

/**
 * 瀑布流事件类型
 */
type WaterfallEventType = 'add' | 'clear' | 'update' | 'resize' | 'columnChange';

/**
 * 瀑布流事件数据
 */
interface WaterfallEvent {
    type: WaterfallEventType;
    data?: {
        item?: HTMLElement;
        count?: number;
        options?: Partial<WaterfallOptions>;
        columns?: number;
        breakpoint?: Breakpoint;
    };
}

/**
 * 瀑布流布局组件
 * @class BreezeWaterfall
 * @description 实现响应式多列瀑布流布局
 * @example
 * const waterfall = new BreezeWaterfall({
 *   container: document.getElementById('container'),
 *   count: 3,
 *   gap: '10px'
 * });
 */
class BreezeWaterfall {
    private container!: HTMLElement;
    private width!: string;
    private count!: number;
    private gap!: string;
    private itemClass!: string;
    private responsive!: boolean;
    private breakpoints!: Breakpoint[];
    private animation!: boolean;
    private animationDuration!: number;
    private observers!: Map<string, Set<Function>>;
    private resizeObserver: ResizeObserver | null = null;
    private items: HTMLElement[] = [];
    private itemRefs: WeakMap<HTMLElement, ItemData> = new WeakMap();
    private resizeTimeout: number | null = null;

    constructor(options: WaterfallOptions) {
        this.validateOptions(options);
        this.initProperties(options);
        this.init();
    }

    /**
     * 验证配置选项
     */
    private validateOptions(options: WaterfallOptions): void {
        if (!options.container) {
            throw new Error('Container element is required');
        }
        if (options.count && options.count <= 0) {
            throw new Error('Column count must be greater than 0');
        }
        if (options.gap && !/^\d+(px|em|rem|%)$/.test(options.gap)) {
            throw new Error('Gap must be a valid CSS length value');
        }
        if (options.breakpoints) {
            options.breakpoints.forEach((bp, index) => {
                if (bp.width <= 0) {
                    throw new Error(`Breakpoint width at index ${index} must be greater than 0`);
                }
                if (bp.columns <= 0) {
                    throw new Error(`Breakpoint columns at index ${index} must be greater than 0`);
                }
            });
        }
    }

    /**
     * 初始化属性
     */
    private initProperties(options: WaterfallOptions): void {
        this.container = options.container;
        this.width = options.width || '100%';
        this.count = options.count || 3;
        this.gap = options.gap || '5px';
        this.itemClass = options.itemClass || 'breeze-waterfall-item';
        this.responsive = options.responsive ?? true;
        this.breakpoints = options.breakpoints || [
            { width: 768, columns: 2 },
            { width: 1024, columns: 3 },
            { width: 1440, columns: 4 }
        ];
        this.animation = options.animation ?? true;
        this.animationDuration = options.animationDuration || 300;
        this.observers = new Map();
    }

    /**
     * 初始化组件
     */
    private init(): void {
        this.setupContainer();
        if (this.responsive) {
            this.initResponsive();
        }
    }

    /**
     * 设置容器样式
     */
    private setupContainer(): void {
        this.container.style.width = this.width;
        this.container.style.columnCount = this.count.toString();
        this.container.style.columnGap = this.gap;
        this.container.style.display = 'block';
        
        // 计算每列的宽度
        const gapValue = parseInt(this.gap);
        const gapUnit = this.gap.replace(/[0-9]/g, '');
        const containerWidth = this.container.clientWidth;
        const columnWidth = (containerWidth - (gapValue * (this.count - 1))) / this.count;
        
        // 添加图片宽度限制
        const style = document.createElement('style');
        style.textContent = `
            .${this.itemClass} {
                width: ${columnWidth}px;
            }
            .${this.itemClass} img {
                width: 100%;
                height: auto;
                display: block;
            }
        `;
        document.head.appendChild(style);
    }

    /**
     * 初始化响应式
     */
    private initResponsive(): void {
        this.resizeObserver = new ResizeObserver(() => {
            if (this.resizeTimeout) {
                clearTimeout(this.resizeTimeout);
            }
            this.resizeTimeout = window.setTimeout(() => {
                this.handleResize();
            }, 10);
        });
        this.resizeObserver.observe(this.container);
    }

    /**
     * 处理窗口大小变化
     */
    private handleResize(): void {
        const width = this.container.clientWidth;
        const newBreakpoint = this.getBreakpointForWidth(width);
        
        // 计算每列的宽度
        const gapValue = parseInt(this.gap);
        const gapUnit = this.gap.replace(/[0-9]/g, '');
        const columnWidth = (width - (gapValue * (this.count - 1))) / this.count;
        
        // 更新项目宽度样式
        const style = document.createElement('style');
        style.textContent = `
            .${this.itemClass} {
                width: ${columnWidth}px;
            }
            .${this.itemClass} img {
                width: 100%;
                height: auto;
                display: block;
            }
        `;
        
        // 移除旧的样式
        const oldStyle = document.querySelector(`style[data-waterfall-style]`);
        if (oldStyle) {
            oldStyle.remove();
        }
        style.setAttribute('data-waterfall-style', '');
        document.head.appendChild(style);
        
        if (newBreakpoint && newBreakpoint.columns !== this.count) {
            this.count = newBreakpoint.columns;
            this.container.style.columnCount = this.count.toString();
            this.emit('resize', { 
                columns: this.count,
                breakpoint: newBreakpoint
            });
        }
    }

    /**
     * 根据宽度获取对应的断点配置
     */
    private getBreakpointForWidth(width: number): Breakpoint | null {
        return this.breakpoints
            .sort((a, b) => b.width - a.width)
            .find(bp => width >= bp.width) || null;
    }

    /**
     * 计算列高
     */
    private calculateColumnHeights(): number[] {
        const columns = Array(this.count).fill(0);
        this.items.forEach(item => {
            const itemData = this.itemRefs.get(item);
            if (itemData) {
                columns[itemData.column] += itemData.height + parseInt(this.gap);
            }
        });
        return columns;
    }

    /**
     * 添加项目
     */
    public addItem(content: string | HTMLElement): HTMLElement {
        const item = document.createElement('div');
        item.className = this.itemClass;
        item.style.breakInside = 'avoid';
        item.style.marginBottom = this.gap;
        
        if (this.animation) {
            item.style.opacity = '0';
            item.style.transition = `opacity ${this.animationDuration}ms ease-in-out`;
        }
        
        if (typeof content === 'string') {
            item.innerHTML = content;
        } else if (content instanceof HTMLElement) {
            item.appendChild(content);
        }
        
        this.container.appendChild(item);
        this.items.push(item);

        // 记录项目数据
        const columnHeights = this.calculateColumnHeights();
        const minHeightIndex = columnHeights.indexOf(Math.min(...columnHeights));
        this.itemRefs.set(item, {
            height: item.offsetHeight,
            column: minHeightIndex,
            index: this.items.length - 1
        });

        // 动画处理
        if (this.animation) {
            requestAnimationFrame(() => {
                item.style.opacity = '1';
            });
        }

        this.emit('add', { item });
        return item;
    }

    /**
     * 批量添加项目
     */
    public addItems(contents: (string | HTMLElement)[]): HTMLElement[] {
        return contents.map(content => this.addItem(content));
    }

    /**
     * 清空所有项目
     */
    public clear(): void {
        while (this.container.firstChild) {
            this.container.removeChild(this.container.firstChild);
        }
        this.items = [];
        this.itemRefs = new WeakMap();
        this.emit('clear');
    }

    /**
     * 更新配置
     */
    public update(options: Partial<WaterfallOptions>): void {
        this.validateOptions({ ...this.getCurrentOptions(), ...options });
        
        if (options.width) this.width = options.width;
        if (options.count) this.count = options.count;
        if (options.gap) this.gap = options.gap;
        if (options.itemClass) this.itemClass = options.itemClass;
        if (options.responsive !== undefined) this.responsive = options.responsive;
        if (options.breakpoints) this.breakpoints = options.breakpoints;
        if (options.animation !== undefined) this.animation = options.animation;
        if (options.animationDuration) this.animationDuration = options.animationDuration;
        
        this.setupContainer();
        this.emit('update', { options });
    }

    /**
     * 获取当前配置
     */
    private getCurrentOptions(): WaterfallOptions {
        return {
            container: this.container,
            width: this.width,
            count: this.count,
            gap: this.gap,
            itemClass: this.itemClass,
            responsive: this.responsive,
            breakpoints: this.breakpoints,
            animation: this.animation,
            animationDuration: this.animationDuration
        };
    }

    /**
     * 获取所有项目
     */
    public getItems(): HTMLElement[] {
        return [...this.items];
    }

    /**
     * 添加事件监听
     */
    public on(event: string, callback: Function): void {
        if (!this.observers.has(event)) {
            this.observers.set(event, new Set());
        }
        this.observers.get(event)?.add(callback);
    }

    /**
     * 移除事件监听
     */
    public off(event: string, callback: Function): void {
        this.observers.get(event)?.delete(callback);
    }

    /**
     * 触发事件
     */
    private emit(event: string, data?: any): void {
        this.observers.get(event)?.forEach(callback => {
            callback(data);
        });
    }

    /**
     * 销毁组件
     */
    public destroy(): void {
        // 清理观察者
        if (this.resizeObserver) {
            this.resizeObserver.disconnect();
            this.resizeObserver = null;
        }
        
        // 清理定时器
        if (this.resizeTimeout) {
            clearTimeout(this.resizeTimeout);
            this.resizeTimeout = null;
        }
        
        // 清理事件监听器
        this.observers.clear();
        
        // 清理 DOM
        this.clear();
        
        // 清理引用
        this.container = null as any;
        this.items = [];
        this.itemRefs = new WeakMap();
    }
}

export default BreezeWaterfall; 